package mi.payment.utils.iso8583;

import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import lainey.ui.utils.LogUtil;
import mi.payment.Constant;
import mi.payment.settings.NetworkDataOperations;
import mi.payment.utils.secure.TerminalSecure;

/**
 * 组包
 */
public class EncodePackage {

    public static Map<String, MsgField> preAssemblyBase(String bitmapHexString) {
        return preAssembly(bitmapHexString, FieldConfig.FieldTypeConfig128);
    }

    /**
     * 根据bitmap字符串组装域
     *
     * @param bitmapHexString bitmap字符串
     * @param fieldConfig     域类型配置表
     * @return 域列表
     */
    public synchronized static Map<String, MsgField> preAssembly(String bitmapHexString, int[][] fieldConfig) {
        boolean[] bitmap = getBinaryFromHexString(bitmapHexString);
        LinkedHashMap<String, MsgField> packageHashMap = new LinkedHashMap<>();
        for (int i = 1; i < bitmap.length; i++) {
            if (bitmap[i]) {
                MsgField outField = new MsgField();
                outField.setFieldPos(i);
                outField.setLengthType(fieldConfig[i][0]);
                outField.setLengthTypeEncode(fieldConfig[i][1]);
                outField.setDataLength(fieldConfig[i][2]);
                outField.setDataType(fieldConfig[i][3]);
                outField.setAlignType(fieldConfig[i][4]);
                outField.setFillChar(fieldConfig[i][5]);
                packageHashMap.put("F" + String.format(Locale.getDefault(), "%03d", i), outField);
            }
        }
        return packageHashMap;
    }

    public synchronized static byte[] assembly(Map<String, MsgField> packageHashMap, String type, int processReq) {
        return assembly(packageHashMap, type, processReq, null);
    }

    /**
     * 組包
     *
     * @param packageHashMap 域列表
     * @param type           消息类型
     * @param processReq     处理要求  {@link TerminalSecure}
     * @return byte数组
     */
    public synchronized static byte[] assembly(Map<String, MsgField> packageHashMap, String type, int processReq, String tPdu) {
        LogUtil.e(Constant.TAG, "消息类型：" + type);
        String tPduStr;
        if (tPdu == null || tPdu.length() != 10) {
            NetworkDataOperations networkDataOperations = NetworkDataOperations.getInstance();
            tPduStr = networkDataOperations.getNetworkParamSettings().getTPdu();
        } else {
            tPduStr = tPdu;
        }
        LogUtil.e(Constant.TAG, "tPdu：" + tPduStr);

        String msgHeaderStart = FieldConfig.MSG_HEADER_START;   // 应用类别定义 N2 软件总版本号 N2 终端状态N1
        String msgHeaderEnd = FieldConfig.MSG_HEADER_VERSION;   // 软件分版本号 N6
        String headerStr = msgHeaderStart + String.valueOf(processReq) + msgHeaderEnd;

        int initLen = 13;
        int typeLength = FieldConfig.FieldTypeConfig128[0][2];
        int typeType = FieldConfig.FieldTypeConfig128[0][3];
        switch (typeType) {
            case FieldConfig.SDK_8583_DATA_BCD:
                if (type.length() != typeLength) {
                    throw new RuntimeException("消息类型数据长度出错");
                }
                initLen += (typeLength + 1) / 2;
                break;
            case FieldConfig.SDK_8583_DATA_ASC:
                if (type.length() != typeLength) {
                    throw new RuntimeException("消息类型数据长度出错");
                }
                initLen += typeLength;
                break;
            case FieldConfig.SDK_8583_DATA_BIT:
                if (type.length() != 2 * typeLength) {
                    throw new RuntimeException("消息类型数据长度出错");
                }
                initLen += typeLength;
                break;
            default:
                break;
        }
        int len = initLen + FieldConfig.FieldTypeConfig128[1][2];

        Iterator iterator = packageHashMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            MsgField msgField = (MsgField) entry.getValue();

            // 判断数据长度与数据类型、数据内容是否匹配
            if (msgField.getLengthType() == 0) {
                if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BIT) {
                    if (2 * msgField.getDataLength() != msgField.getDataStr().length()) {
                        throw new RuntimeException("Field" + msgField.getFieldPos() + "数据长度出错");
                    }
                } else if (msgField.getDataLength() != msgField.getDataStr().length()) {
                    throw new RuntimeException("Field" + msgField.getFieldPos() + "数据长度出错");
                }
            }

            // 计算请求包总长度
            int fieldDataType = msgField.getDataType();
            if (fieldDataType == FieldConfig.SDK_8583_DATA_BCD) {
                if (msgField.getLengthType() > 0) {
                    // 不定长
                    len += (msgField.getLengthType() + 1) / 2 + (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                } else {
                    len += (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                }
            } else if (fieldDataType == FieldConfig.SDK_8583_DATA_BIT) {
                if (msgField.getLengthType() > 0) {
                    // bit 变长时表示字节数组转换成16进制字符串的长度
                    len += (msgField.getLengthType() + 1) / 2 + (msgField.getDataLength() / 2);
                } else {
                    // bit 定长时表示字节的长度，配置表已经算好长度不需要 / 2
                    len += msgField.getDataLength();
                }
            } else {
                if (msgField.getLengthType() > 0) {
                    len += (msgField.getLengthType() + 1) / 2 + msgField.getDataLength();
                } else {
                    len += msgField.getDataLength();
                }
            }
        }

        byte[] body = new byte[len];

        // tPdu
        byte[] tPduBytes = Utils.hexStr2Bytes(tPduStr);
        System.arraycopy(tPduBytes, 0, body, 2, 5);

        // 报文头
        byte[] header = Utils.hexStr2Bytes(headerStr);
        System.arraycopy(header, 0, body, 7, 6);

        byte mt[] = null;
        int mtType = FieldConfig.FieldTypeConfig128[0][3];
        switch (mtType) {
            case FieldConfig.SDK_8583_DATA_BCD:
                int var = (typeLength + 1) / 2;
                int align = FieldConfig.FieldTypeConfig128[0][4];
                mt = new byte[var];
                Utils.BCDEncode(type, mt, align, align);
                break;
            case FieldConfig.SDK_8583_DATA_ASC:
                try {
                    mt = type.getBytes("ISO-8859-1");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                break;
            case FieldConfig.SDK_8583_DATA_BIT:
                mt = Utils.hexStr2Bytes(type);
                break;
            default:
                break;
        }
        System.arraycopy(mt, 0, body, initLen - mt.length, mt.length);

        // 位图
        boolean[] bBitMap = new boolean[65];
        int index = 8 + initLen;
        Iterator it = packageHashMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            MsgField msgField = (MsgField) entry.getValue();
            bBitMap[msgField.getFieldPos()] = true;
            // 变长数据计算变长的长度
            if (msgField.getLengthType() > 0) {
                // 数据是可变长的:拼变长的值
                int dataType = msgField.getDataType();
                if (dataType == FieldConfig.SDK_8583_DATA_BIT) {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength() / 2));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                } else if (dataType == FieldConfig.SDK_8583_DATA_BCD) {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength()));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                } else {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength()));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                }
            }
            LogUtil.e(Constant.TAG, "Pack Field[" + msgField.getFieldPos() + "]: " + msgField.getDataStr());

            // process by field type.
            if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_ASC) {
                try {
                    LogUtil.d(Constant.TAG, " msgField ------ " + entry.getKey());
                    System.arraycopy(msgField.getDataStr().getBytes("ISO-8859-1"), 0, body, index, msgField.getDataLength());
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                index += msgField.getDataLength();
            } else if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BIT) {
                byte dat[] = Utils.hexStr2Bytes(msgField.getDataStr());
                System.arraycopy(dat, 0, body, index, dat.length);
                index += dat.length;
            } else if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BCD) {
                int bcdLen = (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                byte dat[] = new byte[bcdLen];
                Utils.BCDEncode(msgField.getDataStr(), dat, msgField.getAlignType(), msgField.getFillChar());
                System.arraycopy(dat, 0, body, index, bcdLen);
                index += bcdLen;
            }
        }
        byte[] bitmap = Utils.getByteFromBinary(bBitMap);
        System.arraycopy(bitmap, 0, body, initLen, bitmap.length);

        if (packageHashMap.get("F064") != null) {
            TerminalSecure.GenerateMAC(body);
        }

        // 计算报文长度
        body[0] = (byte) ((body.length - 2) / 256);
        body[1] = (byte) ((body.length - 2) % 256);
        return body;
    }


    private static boolean[] getBinaryFromHexString(String bitmapHexString) {
        byte[] bitmapBytes = Utils.hexStr2Bytes(bitmapHexString);
        return Utils.getBinaryFromByte(bitmapBytes);
    }

    /**
     * 根据bitmap字符串组装域
     *
     * @param bitmapHexString bitmap字符串
     * @return 域列表
     */
    public static Map<String, MsgField> preAssembly(String bitmapHexString) {
        boolean[] bitmap = getBinaryFromHexString(bitmapHexString);
        LinkedHashMap<String, MsgField> packageHashMap = new LinkedHashMap<>();
        bitmap[0] = true;
        bitmap[1] = true;
        for (int i = 0; i < bitmap.length; i++) {
            if (bitmap[i]) {
                MsgField outField = new MsgField();
                outField.setFieldPos(i);
                outField.setLengthType(FieldConfig.FieldTypeConfig128[i][0]);
                outField.setLengthTypeEncode(FieldConfig.FieldTypeConfig128[i][1]);
                outField.setDataLength(FieldConfig.FieldTypeConfig128[i][2]);
                outField.setDataType(FieldConfig.FieldTypeConfig128[i][3]);
                outField.setAlignType(FieldConfig.FieldTypeConfig128[i][4]);
                outField.setFillChar(FieldConfig.FieldTypeConfig128[i][5]);
                packageHashMap.put("F" + String.format(Locale.getDefault(), "%03d", i), outField);
            }
        }
        return packageHashMap;
    }

    /**
     * @param msgFront       报文前置数据,bcd码不支持自动补0
     * @param packageHashMap 报问体
     */
    public synchronized static byte[] assembly(List<String> msgFront, LinkedHashMap<String, MsgField> packageHashMap) {
        int megLen = 0; // 报文字节数
        int messageFrontLen = FieldConfig.MessageFront.length;
        // 第0列不算
        for (int i = 1; i < messageFrontLen; i++) {
            switch (FieldConfig.MessageFront[i][1]) {
                case FieldConfig.SDK_8583_DATA_ASC:
                    if (msgFront.get(i).length() != FieldConfig.MessageFront[i][0]) {
                        throw new RuntimeException("FieldConfig.MessageFront" + i + "数据长度出错");
                    }
                    megLen += FieldConfig.MessageFront[i][0];
                    break;
                case FieldConfig.SDK_8583_DATA_BIT:
                    if (msgFront.get(i).length() != 2 * FieldConfig.MessageFront[i][0]) {
                        throw new RuntimeException("FieldConfig.MessageFront" + i + "数据长度出错");
                    }
                    megLen += FieldConfig.MessageFront[i][0];
                    break;
                case FieldConfig.SDK_8583_DATA_BCD:
                    if (msgFront.get(i).length() != FieldConfig.MessageFront[i][0]) {
                        throw new RuntimeException("FieldConfig.MessageFront" + i + "数据长度出错");
                    }
                    megLen += FieldConfig.MessageFront[i][0] / 2;
                    break;
                default:
                    break;
            }
        }
        megLen += FieldConfig.MessageFront[0][0]; // 加报文长度字节的长度

        // 位图
        MsgField bitmapMsgField = packageHashMap.get("F001");
        if (bitmapMsgField == null) throw new RuntimeException("位图元素为空出错");
        bitmapMsgField.setDataStr(String.format("%0" + 2 * bitmapMsgField.getDataLength() + "d", 0));

        Iterator iterator = packageHashMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            MsgField msgField = (MsgField) entry.getValue();
            // 判断数据长度与数据类型、数据内容是否匹配
            if (msgField.getLengthType() == 0) {
                if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BIT) {
                    if (2 * msgField.getDataLength() != msgField.getDataStr().length()) {
                        throw new RuntimeException("Field" + msgField.getFieldPos() + "数据长度出错");
                    }
                } else if (msgField.getDataLength() != msgField.getDataStr().length()) {
                    throw new RuntimeException("Field" + msgField.getFieldPos() + "数据长度出错");
                }
            }

            // 计算请求包总长度
            int fieldDataType = msgField.getDataType();
            if (fieldDataType == FieldConfig.SDK_8583_DATA_BCD) {
                if (msgField.getLengthType() > 0) {
                    megLen += (msgField.getLengthType() + 1) / 2 + (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                } else {
                    megLen += (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                }
            } else if (fieldDataType == FieldConfig.SDK_8583_DATA_BIT) {
                if (msgField.getLengthType() > 0) {
                    // bit 变长时表示字节数组转换成16进制字符串的长度
                    megLen += (msgField.getLengthType() + 1) / 2 + (msgField.getDataLength() / 2);
                } else {
                    // bit 定长时表示字节的长度
                    megLen += msgField.getDataLength();
                }
            } else {
                if (msgField.getLengthType() > 0) {
                    megLen += (msgField.getLengthType() + 1) / 2 + msgField.getDataLength();
                } else {
                    megLen += msgField.getDataLength();
                }
            }
        }

        byte[] body = new byte[megLen]; // 分配报文空间
        int index = FieldConfig.MessageFront[0][0]; // 报文代表长度的字节
        // 填充报文前置部分数据//第0列不算
        for (int i = 1; i < messageFrontLen; i++) {
            byte[] value = new byte[0];
            switch (FieldConfig.MessageFront[i][1]) {
                case FieldConfig.SDK_8583_DATA_ASC:
                    try {
                        value = msgFront.get(i - 1).getBytes("ISO-8859-1");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    break;
                case FieldConfig.SDK_8583_DATA_BIT:
                case FieldConfig.SDK_8583_DATA_BCD:
                    value = Utils.hexStr2Bytes(msgFront.get(i - 1));
                    break;
                default:
                    break;
            }
            System.arraycopy(value, 0, body, index, value.length);
            index += value.length;
        }

        // 消息类型
        MsgField typeMsgField = packageHashMap.get("F000");
        if (typeMsgField == null) throw new RuntimeException("消息类型元素为空出错");
        boolean[] bbitMap = new boolean[bitmapMsgField.getDataLength() + 1];
        int bitmapIndex = megLen + typeMsgField.getDataLength() + bitmapMsgField.getDataLength();
        Iterator iterator1 = packageHashMap.entrySet().iterator();

        while (iterator1.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator1.next();
            MsgField msgField = (MsgField) entry.getValue();
            bbitMap[msgField.getFieldPos()] = true;
            // 变长数据计算变长的长度
            if (msgField.getLengthType() > 0) {
                // 数据是可变长的:拼变长的值
                int dataType = msgField.getDataType();
                if (dataType == FieldConfig.SDK_8583_DATA_BIT) {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength() / 2));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                } else if (dataType == FieldConfig.SDK_8583_DATA_BCD) {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength()));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                } else {
                    byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength()));
                    System.arraycopy(varValue, 0, body, index, varValue.length);
                    index += varValue.length;
                }

//                    if (msgField.getFieldPos() != 55) {
//                        byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength()));
//                        System.arraycopy(varValue, 0, body, index, varValue.length);
//                        index += varValue.length;
//                    } else {
//                        byte[] varValue = Utils.StrToBCDBytes(String.format("%0" + msgField.getLengthType() + "d", msgField.getDataLength() / 2));
//                        System.arraycopy(varValue, 0, body, index, varValue.length);
//                        index += varValue.length;
//                    }
            }

            LogUtil.e(Constant.TAG, "Pack Field[" + msgField.getFieldPos() + "]: " + msgField.getDataStr());

            // process by field type.
            if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_ASC) {
                try {
                    System.arraycopy(msgField.getDataStr().getBytes("ISO-8859-1"), 0, body, index, msgField.getDataLength());
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                index += msgField.getDataLength();
            } else if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BIT) {
                byte dat[] = Utils.hexStr2Bytes(msgField.getDataStr());
                System.arraycopy(dat, 0, body, index, dat.length);
                index += dat.length;
            } else if (msgField.getDataType() == FieldConfig.SDK_8583_DATA_BCD) {
                int bcdLen = (msgField.getDataLength() / 2) + (msgField.getDataLength() % 2);
                byte dat[] = new byte[bcdLen];
                Utils.BCDEncode(msgField.getDataStr(), dat, msgField.getAlignType(), msgField.getFillChar());
                System.arraycopy(dat, 0, body, index, bcdLen);
                index += bcdLen;
            }
        }
        bbitMap[0] = false;
        bbitMap[1] = false;
        byte[] bitmap = Utils.getByteFromBinary(bbitMap);
        System.arraycopy(bitmap, 0, body, bitmapIndex, bitmap.length);
        if (packageHashMap.get("F064") != null) {
            TerminalSecure.GenerateMAC(body);
        }
        // 计算报文长度,本框架最大支持4个字节
        int bodyLen = body.length - FieldConfig.MessageFront[0][0];
        int lenLen = FieldConfig.MessageFront[0][0];
        switch (FieldConfig.MessageFront[0][1]) {
            case FieldConfig.SDK_8583_DATA_BIT:
                for (int i = 0; i < lenLen; i++) {
                    body[i] = (byte) ((bodyLen >> (8 * (lenLen - 1 - i))) & 0xFF);
                }
                break;
            case FieldConfig.SDK_8583_DATA_BCD:
                String bcdStr = String.format("%0" + lenLen + "d", bodyLen);
                byte[] value = Utils.hexStr2Bytes(bcdStr);
                System.arraycopy(value, 0, body, 0, value.length);
                break;
            default:
                break;
        }
        // 计算报文长度
//        body[0] = (byte) ((body.length - 2) / 256);//获取高位
//        body[1] = (byte) ((body.length - 2) % 256);//获取低位
        //------- 与下面的方式等价 ----------//
//        body[0] = (byte) (((body.length - 2) & 0xFF00)>>8);
//        body[1] = (byte) ((body.length - 2) & 0xFF);
        return body;
    }
}
